package com.github.ylt.protocol.http;

import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

public class Headers implements Map<String, List<String>>{
    Map<String, List<String>> headers;
    public Headers() {
        headers = new HashMap<>(32);
    }

    public Headers(Map<String, List<String>> headers) {
        Objects.requireNonNull( headers );
        Map<String, LinkedList<String>> collect = headers.entrySet().stream().collect(Collectors.toUnmodifiableMap(Entry::getKey, e -> new LinkedList<>(e.getValue())));
        this.headers = new HashMap<>(32);
        this.putAll(collect);
    }

    public static Headers of(String ... headers){
        Objects.requireNonNull( headers );
        int length = headers.length;
        if(length == 0){
            return new ImmutableHeaders(new Headers());
        }
        if(length%2 != 0){
            throw new IllegalArgumentException("数量不对请按照键值的顺序放入如：key,value,key2,value2");
        }
        var header = new Headers();
        for (int i = 0; i < length; i+=2) {
            String key = headers[i];
            String value = headers[i+1];
            header.add(key, value);
        }
        return new ImmutableHeaders(header);
    }

    public static Headers of(Map<String, List<String>> headers) {
        Objects.requireNonNull( headers );
        return new ImmutableHeaders(new Headers(headers));
    }


    /**
     * 规范协议头
     * @param header 完整http协议头
     * @return 返回正确的http协议头
     */
    public static String normal(String header){
        Objects.requireNonNull(header,"header不能为空");
        if("SOAPACTION".equals(header)){
            return header;
        }
        char[] charArray = header.toCharArray();
        int length = charArray.length;
        // http协议中的头每个首字母为大写
        if(charArray[0] >= 'a' && charArray[0] <= 'z'){
            charArray[0] = (char)(charArray[0] - ('a' - 'A'));
        }
        // 其余字母为小写
        for(int i = 1; i < length; i++){
            if(charArray[i-1] == '-' && charArray[i] >= 'a' && charArray[i] <= 'z'){
                charArray[i] = (char)(charArray[i] - ('a' - 'A'));
            }else if(charArray[i-1] != '-' && charArray[i] >= 'A' && charArray[i] <= 'Z'){
                charArray[i] = (char)(charArray[i] + ('a' - 'A'));
            }
        }
        return new String(charArray);
    }

    /**
     * 检查协议值是否正确
     * @param value 完整的协议值
     */
    public static void checkValue(String value) {
        if ( value == null ) {
            throw new IllegalArgumentException( "value不能为空！！" );
        }
        int length = value.length();
        for ( int i = 0; i < length; i++ ) {
            char c = value.charAt( i );
            if ( c == '\r' ) {
                if(i == length - 2){
                    throw new IllegalArgumentException("出现非法字符");
                }
                c = value.charAt( i + 2 );
                if ( c != '\n' ) {
                    throw new IllegalArgumentException("出现非法字符");
                }
                i+=2;
            }else if( c == '\n' ){
                throw new IllegalArgumentException("没有发现\\r,请按照协议规范书写");
            }
        }
    }

    /**
     * 存入协议头
     * @param key 协议头名称
     * @param value 协议头值
     */
    public void add(String key, String value){
        checkValue(value);
        Objects.requireNonNull( key );
        Objects.requireNonNull( value );
        String normal = normal(key);
        List<String> values = this.headers.computeIfAbsent(normal, k -> new LinkedList<>());
        values.add(value);
    }

    @Override
    public int size() {
        return headers.size();
    }

    @Override
    public boolean isEmpty() {
        return headers.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        Objects.requireNonNull(key, "key不能为空！！");
        return key instanceof String && headers.containsKey(normal((String) key));
    }

    @Override
    public boolean containsValue(Object value) {
        Objects.requireNonNull(value, "value不能为空！！");
        return headers.containsValue(value);
    }

    @Override
    public List<String> get(Object key) {
        return headers.get((String) key);
    }

    @Override
    public List<String> put(String key, List<String> value) {
        Objects.requireNonNull( key );
        Objects.requireNonNull( value );
        for (String v:value){
            checkValue( v );
        }
        return headers.put(normal(key), value);
    }

    @Override
    public List<String> remove(Object key) {
        return headers.remove(key);
    }

    @Override
    public void putAll(Map<? extends String, ? extends List<String>> m) {
        m.forEach(this::put);
    }

    @Override
    public void clear() {
        headers.clear();
    }

    @Override
    public Set<String> keySet() {
        return headers.keySet();
    }

    @Override
    public Collection<List<String>> values() {
        return headers.values();
    }

    @Override
    public Set<Entry<String, List<String>>> entrySet() {
        return headers.entrySet();
    }

    @Override
    public boolean equals(Object o) {
        return headers.equals(o);
    }

    @Override
    public int hashCode() {
        return headers.hashCode();
    }

    @Override
    public void replaceAll(BiFunction<? super String, ? super List<String>, ? extends List<String>> function) {
        BiFunction<? super String, ? super List<String>, ? extends List<String>> biFunction = function.andThen(value -> {
            Objects.requireNonNull(value, "");
            value.forEach(Headers::checkValue);
            return value;
        });
        Map.super.replaceAll(biFunction);
    }
}
